// hpowernetsolver.h
#pragma once

/*
 * Copyright 2012,2013 - Espen Harlinn, All rights reserved
 *
 * Ongoing work ...
 *
 *
 *
 */

#ifndef __HPOWERNETSOLVER_H__
#define __HPOWERNETSOLVER_H__

#include "hpowerdef.h"
#include "hwinstring.h"
#include "hwindatetime.h"
#include "hwincomponent.h"
#include <array>

namespace harlinn
{
    namespace power
    {
        namespace network
        {
            using namespace harlinn::windows;
            typedef std::complex<double> complex;

            typedef std:: array<double,3> VectorD3;
            typedef std:: array<complex,3> VectorC3;
            typedef std:: array<std ::array<double,3>,3> MatrixD3x3;
            typedef std:: array<std ::array<complex,3>,3> MatrixC3x3;

            enum class Phase : int
            {
                None = 0,
                A = 1,
                B = 2,
                C = 4,
                ThreePhase = A | B | C,
                N = 8,
                ThreePhaseN = ThreePhase | N,

                //split phase
                S1	= 0x0010,
                S2	= 0x0020,
                SN	= 0x0040,
                S	= 0x0070,
                Ground = 0x0080,
                Delta = 0x0100
            };
            DEFINE_ENUM_FLAG_OPERATORS(Phase)

            enum class Condition : int
            {
                Normal = 0,
                Contact = 0x1000,
                PhaseAContact = static_cast<int>(Phase::A) | Contact,
                PhaseBContact = static_cast<int>(Phase::B) | Contact,
                PhaseCContact = static_cast<int>(Phase::C) | Contact,
                NeutralContact = static_cast<int>(Phase::N) | Contact,
                Split1Contact = static_cast<int>(Phase::S1) | Contact,
                Split2Contact = static_cast<int>(Phase::S2) | Contact,
                SplitNContact = static_cast<int>(Phase::SN) | Contact,
                GroundContact = static_cast<int>(Phase::Ground) | Contact,
                ContactMask = 0x10ff,
                Open =  0x2000,
                PhaseAOpen = static_cast<int>(Phase::A) | Open,
                PhaseBOpen = static_cast<int>(Phase::B) | Open,
                PhaseCOpen = static_cast<int>(Phase::C) | Open,
                NeutralOpen = static_cast<int>(Phase::N) | Open,
                Split1Open = static_cast<int>(Phase::S1) | Open,
                Split2Open = static_cast<int>(Phase::S2) | Open,
                SplitNOpen = static_cast<int>(Phase::SN) | Open,
                GroundOpen = static_cast<int>(Phase::Ground) | Open,
                OpenMask = 0x20ff,
                ConditionMask = 0x3000
            };
            DEFINE_ENUM_FLAG_OPERATORS(Condition)

            template<typename T>
            struct Range
            {
                typedef T value_type;
                value_type low;
                value_type high;

                Range()
                    : low(T()),
                      high(T())
                {}

                Range(const T& theLowValue, const T& theHighValue)
                    : low(theLowValue),
                      high(theHighValue)
                {}


            };


            // -----------------------------------------------------------------
            // PowerElement
            // -----------------------------------------------------------------
            class PowerElement : public Component
            {
                Phase phases;
                Condition conditions;
                double nominalVoltage;
                int solutionCode;
                DateTime timeStamp;
                DateTime previousTimeStamp;
            public:
                typedef Component Base;

                PowerElement()
                    : phases(Phase::None),
                    conditions(Condition::Normal),
                    nominalVoltage(0.0),
                    solutionCode(-1),
                    timeStamp(DateTime::MinValue),
                    previousTimeStamp(DateTime::MinValue)
                {}

                Phase Phases() const { return phases; }
                PowerElement& SetPhases(Phase thePhases ) { phases = thePhases; return *this; }

                Condition Conditions() const { return conditions; }
                PowerElement& SetConditions(Condition theConditions) { conditions = theConditions; return *this; }

                double NominalVoltage() const { return nominalVoltage; }
                PowerElement& SetNominalVoltage(double theNominalVoltage) { nominalVoltage = theNominalVoltage; return *this; }

                int SolutionCode() const { return solutionCode; }
                PowerElement& SetSolutionCode(int theSolutionCode) { solutionCode = theSolutionCode; return *this; }

                DateTime TimeStamp() const { return timeStamp; }
                PowerElement& SetTimeStamp( const DateTime& theValue ) { timeStamp = theValue; return *this; }

                DateTime PreviousTimeStamp() const { return previousTimeStamp; }
                PowerElement& SetPreviousTimeStamp( const DateTime& theValue ) { previousTimeStamp = theValue; return *this; }
                TimeSpan TimeStep() const { TimeSpan result = timeStamp - previousTimeStamp; return result; }


                virtual PowerElement& Evaluate(const DateTime& theTimeStamp )
                {
                    previousTimeStamp = timeStamp;
                    timeStamp = theTimeStamp;
                    return *this;
                }

            };


            enum class NodeElementType
            {
                PQ = 0, 
                PV = 1, 
                Swing = 2
            };

            enum class NodeElementFlags
            {
                None = 0,
                HasSource = 1
            };

            enum class NodeElementStatus 
            {	
                // voltage is nominal
                Nominal = 1,
                // voltage is too low
			    Undervolt,
                // voltage is too high
			    Overvolt,
	        };
	        enum class NodeElementServiceStatus
            { 
                // The node is out of service
		        OutOfService = 0,
                // The node is operational
		        InService = 1, 
	        };


            enum class NodeElementSubType
            {
                // not a child node
		        None = 0,
                // a child node
		        Child = 1,
                // a child node which has not been linked
		        ChildNoInit = 2,
                // a parent of a child
		        Parent = 3,
                // a child node with different 
                // phase-connection than the parent
		        DiffChild = 4,
                // a parent node with different 
                // phase-connection than the child
		        DiffParent = 5
		    };



            // -----------------------------------------------------------------
            // NodeElement
            // -----------------------------------------------------------------
            class EdgeElement;
            class NodeElement : public PowerElement
            {

            public:
                // voltage at last pass
	            VectorC3 previousVoltage;
                // current injection: shunt+power+current
	            VectorC3 currentInjection;
                // Previous timestep for propogating child node properties
	            DateTime previousTimestep;
                // Previous power values - for child node propogation
	            MatrixC3x3 previousChildPower;
                // Previous current value - Phase 1&2 current injections 
                // for child node propogation in triplex mode
	            complex previousChildCurrent12;
            
                // frequency if this is a reference bus
	            double frequency;
                // reference bus defining the frequency
	            NodeElement* referenceBus;

	            static unsigned int totalNodeCount;

                // number of links connecting to this node
	            unsigned short k;

                // Previous voltage value for Master/Slave functionality
	            std::vector<complex> previousVoltageValue;
                // Power value for Master/Slave functionality
	            std::vector<complex> previousPowerValue;
            
	            // Last time the node was out of service
	            DateTime previousDisconnect;
                // last total uptime
	            double previousUptime;
                // current uptime
	            double currentUptime;

	            NodeElementSubType SubNode;
                NodeElementFlags busflags;
                NodeElementStatus status;
                NodeElementServiceStatus serviceStatus;


                // flags for reconvergent input lines
                Phase busPhasesIn;
                // flags for output lines
	            Phase busPhasesOut;
                // convergence voltage limit
	            double maximumVoltageError; 

	            // bus voltage to ground
                VectorC3 voltage;
                // bus voltage delta
	            VectorC3 voltageDelta;	
                // bus current injection (>= 0 -> in)
	            VectorC3 current;
                // bus power injection (>= 0 -> in)
	            VectorC3 power;
                // bus shunt admittance 
	            VectorC3 shunt;

                // Phase 1&2 current injections 
                // in triplex mode
	            complex current12;

                // Include nominal residential 
                // currents for angle adjustments
	            VectorC3 nominalResidentialCurrents;

                // Extra current calculation information for triplex lines
	            std::vector<complex> triplexData;	
                // extra calculation data
	            std::vector<complex> extraData;

                // child node list
                std::vector<NodeElement*> children;

                NodeElement* parent;
	            std::vector<EdgeElement*> links;
	            
	            // mean repair time
                TimeSpan meanRepairTime;

                // Index of matching Node
	            int index;		

                // Index of parent Node
	            int parentIndex;

                // Phase tracking for reliability 
                Phase previousPhases;	

                inline bool isSplit() const
                {
                    return (Phases() & Phase::S) != Phase::None;
                }
            };


            // -----------------------------------------------------------------
            // GeneratorMode
            // -----------------------------------------------------------------
            enum class GeneratorMode
            {
                ConstantVoltage = 1, 
                ConstantPQ = 2, 
                ConstantPF = 4, 
                SupplyDriven = 5
            };

            // -----------------------------------------------------------------
            // GeneratorStatus
            // -----------------------------------------------------------------
            enum class GeneratorStatus
            {
                Offline = 0,
                Online = 1
            };

            // -----------------------------------------------------------------
            // GeneratorPowerType
            // -----------------------------------------------------------------
            enum class GeneratorPowerType
            {
                DC = 1,
                AC = 2
            };

            // -----------------------------------------------------------------
            // GeneratorElement
            // -----------------------------------------------------------------
            class GeneratorElement : public NodeElement
            {
            public:
                Phase phases;
	            GeneratorMode mode;
                GeneratorStatus status;
	            GeneratorPowerType powerType;

	            double rInternal;
	            double rLoad;
	            complex maxVoltage;
	            complex maxCurrent;

	            double frequency;
	            double maxFrequency;
	            double minFrequency;
	            double KV;
	            double powerAngle;
	
                // maximum real power capacity
	            double maxPower;
                // minimum real power capacity
                double minPower;
	
                // maximum reactive power capacity
	            double maxReactivePower;
                // minimum reactive power capacity
                double minReactivePower;
                // nominal rated capacity
	            double ratedkVA;
	
	            double efficiency;
	
	            complex EAInternal;
	            complex EBInternal;
	            complex ECInternal;

                // Voltage
	            complex phaseAVOut;
	            complex phaseBVOut;
	            complex phaseCVOut;
	            
	            // current
	            complex phaseAIOut;
	            complex phaseBIOut;
	            complex phaseCIOut;

                // power
	            complex powerAOut;
	            complex powerBOut;
	            complex powerCOut;

	            complex VAOut;

	            double pfOut;

                // three voltages on three lines
                MatrixC3x3 circuitVoltages;
	
                // the three current on three lines
                MatrixC3x3 lineCurrents;
            };


            // -----------------------------------------------------------------
            // LoadElement
            // -----------------------------------------------------------------
            class LoadElement : public NodeElement
            {
            public:
                complex voltageA;
	            complex voltageB;
	            complex voltageC;
	            complex voltageAB;	
	            complex voltageBC;
	            complex voltageCA;

                VectorD3 basePower;

	            VectorD3 powerLoad;
	            VectorD3 currentLoad;
	            VectorD3 impedanceLoad;

                VectorD3 powerFraction;
	            VectorD3 impedanceFraction;
	            VectorD3 currentFraction;
	            
	            VectorD3 powerPreviousFraction;
	            VectorD3 currentPreviousFraction;
	            VectorD3 impedancePreviousFraction;
	            
	            
            };

            // -----------------------------------------------------------------
            // LoadBusElement (PQ Load)
            // -----------------------------------------------------------------
            class LoadBusElement : public LoadElement
            {
            public:
                std::array<double,6> impedanceP;
	            std::array<double,6> impedanceQ;
	            std::array<double,6> currentM;
	            std::array<double,6> currentA;
	            std::array<double,6> powerP;
	            std::array<double,6> powerQ;

	            double Zp; 
                double Zq; 
                double Im; 
                double Ia; 
                double Pp; 
                double Pq;
	            complex kZ; 
                complex kI; 
                complex kP;
            };


            // -----------------------------------------------------------------
            // TriplexNodeElement
            // -----------------------------------------------------------------
            class TriplexNodeElement : public NodeElement
            {
            public:
                VectorC3 impedance;
	            VectorC3 shuntImpedance;
            };


            // -----------------------------------------------------------------
            // CapacitorControl
            //  operation strategy
            // -----------------------------------------------------------------
            enum class CapacitorControl
            {
                Manual = 0, 
                VAr = 1, 
                Volt = 2, 
                VArVolt = 3, 
                Current = 4,
                Individual = 8 //bank or individual control
            };

            // -----------------------------------------------------------------
            // CapacitorSwitch
            // -----------------------------------------------------------------
            enum class CapacitorSwitch
            {
                Open = 0,
                Closed = 1
            };

            // -----------------------------------------------------------------
            // CapacitorSwitchState
            // -----------------------------------------------------------------
            class CapacitorSwitchState
            {
            public:
                // The current state
                CapacitorSwitch current;
                // The previous state
                CapacitorSwitch previous;
                // The initial state
                CapacitorSwitch initial;

                // The next state
                CapacitorSwitch next;

                // The requested next state
                CapacitorSwitch requestedNext;

                bool changed() const
                {
                    return current != previous;
                }
            };


            // -----------------------------------------------------------------
            // CapacitorPhaseInfo
            // -----------------------------------------------------------------
            class CapacitorPhaseInfo
            {
            public:
                CapacitorSwitchState state;
                double capacitance;
                complex admittance;
                double var;
                double current;
                TimeSpan lockoutInterval;
            };


            // -----------------------------------------------------------------
            // CapacitorElement
            // -----------------------------------------------------------------
            class CapacitorElement : public NodeElement
            {
            public:
	            Phase phasePT;
	            Phase connectedPhases;		
                // voltage set points for voltage control 
                //   low : turn on
                //   high : turn off
                Range<double> voltageSetPoints;
	            // VAR set points for VAR control
                //   low : turn on
                //   high : turn off
	            Range<double> varSetPoints;
                // current set points for current control
                //   low : turn off
                //   high : turn on
	            Range<double> currentSetPoints;	
	            
	            CapacitorControl control;
	            
                CapacitorPhaseInfo a;
                CapacitorPhaseInfo b;
                CapacitorPhaseInfo c;

	            Component* remoteSensor;
	            Component* secondaryRemote;

	            TimeSpan timeDelay;
	            TimeSpan dwellTime;
	            TimeSpan lockoutTime;
            
	            NodeElement* remoteNode;
                EdgeElement* remoteLink;
            };


            // -----------------------------------------------------------------
            // SubstationReferencePhase
            // -----------------------------------------------------------------
            enum class SubstationReferencePhase
            {
                A = 1,
                B = 2,
                C = 3
            };

            // -----------------------------------------------------------------
            // SubstationElement
            // -----------------------------------------------------------------
            class SubstationElement : public NodeElement
            {
            public:
	            DateTime timeStamp;
            
                // The positive sequence voltage of the substation object
	            complex positiveSequenceVoltage;
                // The point of reference for the positive 
                // sequence voltage conversion
	            SubstationReferencePhase referencePhase;

                // average constant power load
	            complex averageTransmissionPowerLoad;
                // average constant impedance load
	            complex averageTransmissionImpedanceLoad;
                // average constant current load
	            complex averageTransmissionCurrentLoad;
                // average of the loads on all three phases 
	            complex averageDistributionLoad;

	            complex distributionPowerA;					
	            complex distributionPowerB;					
	            complex distributionPowerC;	
                
	            VectorC3 sequenceVoltages;
	            double distributionRealEnergy;
	            double basePower;

                // Threshold of convergence for pw load connected items
	            double powerConvergence;
                

                // The angle to shift the sequence voltages by
	            complex referenceAngle;
                // the transformation matrix used to convert 
                // sequence voltages to phase voltages
	            MatrixC3x3 sequenceVoltagesTransform;
	            complex previousPowerA;
	            complex previousPowerB;
	            complex previousPowerC;
	            complex voltageA;
	            complex voltageB;
	            complex voltageC;

	            complex constantPowerLoad;
	            complex constantCurrentLoad;
	            complex constantImpedanceLoad;
                
	            double transformerNominalVoltage;
            };


            // -----------------------------------------------------------------
            // MeterElement
            // -----------------------------------------------------------------
            class MeterElement : public NodeElement
            {
            public:
                // measured voltage
                VectorC3 voltage;
                // measured voltage drop between lines
	            VectorC3 voltageDelta;	
                // measured current
	            VectorC3 current;
                // metered real energy consumption
	            double realEnergy;
                // metered reactive energy consumption
	            double reactiveEnergy;
                // metered power
	            complex power;
                // metered real power
	            double realPower;
                // metered reactive power
	            double reactivePower;
                // metered demand (peak of power)
	            double peakOfPower;
                
                // previous metered real power
	            double previousRealPower; 
                // metered power on each phase
	            VectorC3 powerOnPhase;
                // Reliability flag 
	            bool interrupted;
                // Reliability flag 
	            bool momentarilyInterrupted;
            };


            // -----------------------------------------------------------------
            // TriplexMeterElement
            // -----------------------------------------------------------------
            class TriplexMeterElement : public TriplexNodeElement
            {
            };




            enum class EdgeElementType
            {
                // normal link/transformer
		        Normal = 0,
                // regulator
		        Regulator = 1,
                // Delta-Gwye transformer
		        DeltaGwye = 2,
                // split-phase transformer
		        SplitPhase = 3,
                // Switch
		        Switch = 4
            };

            // flow directions
            enum class EdgeElementFlowDirection
            {
                // Flow is undetermined
                Unknown		= 0x000,
                // A flow information
                PhaseAMask		= 0x00f,
                // Flow over phase A is normal
                PhaseANormal	= 0x001,
                // Flow over phase A is reversed
                PhaseAReverse	= 0x002,
                // No flow over of phase A 
                PhaseANone		= 0x003,
                // B flow information
                PhaseBMask		= 0x0f0,
                // Flow over phase B is normal
                PhaseBNormal	= 0x010,
                // Flow over phase B is reversed
                PhaseBReverse	= 0x020,
                // No flow over of phase B 
                PhaseBNone		= 0x030,
                // phase C flow information
                PhaseCMask		= 0xf00,
                // Flow over phase C is normal
                PhaseCNormal	= 0x100,
                // Flow over phase C is reversed
                PhaseCReverse	= 0x200,
                // No flow over of phase C 
                PhaseCNone		= 0x300	
            };
            DEFINE_ENUM_FLAG_OPERATORS(EdgeElementFlowDirection)


            enum class EdgeElementStatus
            {
                // indicates an impedance change / line contact
                ImpedanceChanged	= 1,
                // indicates line contact 
                LineContact			= 2,
                // use this status to indicate a controller failure
                ControlFailed		= 4
            };
            DEFINE_ENUM_FLAG_OPERATORS(EdgeElementStatus)

            class EdgeElementRatings
            {
                double continuous;
	            double emergency;
            public:
                EdgeElementRatings()
                    : continuous(0.0),
                      emergency(0.0)
                {}

                EdgeElementRatings(double theContinuous, double theEmergency )
                    : continuous(theContinuous),
                      emergency(theEmergency)
                {}

                double Continuous() const { return continuous; }
                EdgeElementRatings& SetContinuous( double theValue ) { continuous = theValue; return *this; }

                double Emergency() const { return emergency; }
                EdgeElementRatings& SetEmergency( double theValue ) { emergency = theValue; return *this; }


            };


            class EdgeElement : public PowerElement
            {
            public:
                // The 'a' matrix
	            MatrixC3x3 a;
                // The 'b' matrix
	            MatrixC3x3 b;
                // The 'c' matrix
	            MatrixC3x3 c;
                // The 'd' matrix
	            MatrixC3x3 d;
                // The 'A' matrix
	            MatrixC3x3 A;
                // The 'B' matrix
	            MatrixC3x3 B;

                // Used to calculate return current
	            VectorC3 tn;

                // transition to admittance
	            MatrixC3x3 toY;

                // transition from admittance
	            MatrixC3x3 fromY;

                // admittance as seen from the "from" side when the edge is a transformer
	            MatrixC3x3 fromYS;
                // admittance as seen from the "to" side when the edge is a transformer
	            MatrixC3x3 toYS;

                // voltage ratio
	            double voltageRatio;

                // Index of Edge
	            int index;

                // Flag for exceptions to the normal handling
	            EdgeElementType type;	

                // Direction of the powerflow
	            EdgeElementFlowDirection flowDirection;

	            double faultCurrentSolved;
	            
	            TimeSpan meanRepairTime;
                
	            EdgeElementRatings edgeLimits;
	            EdgeElementRatings edgeRatings;
	            
            public:
                // Edge status 
	            EdgeElementStatus status;

                // Previous status to detect recalculation 
	            EdgeElementStatus previousStatus;

                // indicates that current has been calculated
	            bool currentAccumulated;

                // do we need to take edge limits into account?
	            bool checkEdgeLimits;
                // source node
	            NodeElement *from;
                //load node
	            NodeElement *to; 

                // current flow into the edge from the source 
	            VectorC3 currentIn;

                // current flow out of the link into the load node
	            VectorC3 currentOut;

                // Target current flow into the edge from the source
	            VectorC3 targetCurrentIn;	

                // Target current flow out of the edge into the load
	            VectorC3 targetCurrentOut;

                // fault current flow into the edge from the source
	            VectorC3 faultCurrentIn;	

                // fault current flow out of the edge into the load
	            VectorC3 faultCurrentOut;

                // power flow into the edge from the source
	            complex powerIn;

                // power flow out of the edge into the load
	            complex powerOut;
                // power loss in a transformer
	            complex powerLoss;

                // individual quantities of the power flow
	            VectorC3 individualPowerIn;
	            VectorC3 individualPowerOut;
	            VectorC3 individualPowerLoss;

                // reliability: index of the protection objects 
                // for the different phase faults
	            std::array<int,3> protectionIndexes;

            public:
	            // Which phases were affected by status change 
	            Phase affectedPhases;
	            
                // Resistance when status==EdgeStatus::ImpedanceChanged 
	            double resistance;
	            
                // Indicates how line was connected
	            Phase connectedPhases;

            };


            // -----------------------------------------------------------------
            // Conductor
            // -----------------------------------------------------------------
            class Conductor
            {
                double geometricMeanRadius;
                EdgeElementRatings winter;
                EdgeElementRatings emergencyWinter;
                EdgeElementRatings summer;
                EdgeElementRatings emergencySummer;
            };


            // -----------------------------------------------------------------
            // LineConductor
            // -----------------------------------------------------------------
            class LineConductor : public Conductor
            {
                double diameter;
	            double resistance;
	            

	            
            };

            // -----------------------------------------------------------------
            // OverheadLineConductor
            // -----------------------------------------------------------------
            class OverheadLineConductor : public LineConductor
            {
	            
            };

            // -----------------------------------------------------------------
            // UndergroundLineConductor
            // -----------------------------------------------------------------
            class UndergroundLineConductor : public LineConductor
            {
                double outerDiameter;

	            double neutralGeometricMeanRadius;
	            double neutralDiameter;
	            double neutralResistance;
	            short  neutralStrands;
	            double insulationRelativePermitivity;
	            double shieldGeometricMeanRadius;
	            double shieldResistance;
	            
            };


            // -----------------------------------------------------------------
            // TriplexLineConductor
            // -----------------------------------------------------------------
            class TriplexLineConductor : public Conductor
            {
                double resistance;
	            
	            
            };


            // -----------------------------------------------------------------
            // LineSpacing
            // -----------------------------------------------------------------
            class LineSpacing
            {

                // distance between cables:
                //   A and B
                double aToB;
                //   B and C
	            double bToC;
                //   A and C
	            double aToC;

                //   A and Neutral
	            double aToN;
                //   B and Neutral
	            double bToN;
                //   C and Neutral
	            double cToN;

                // distance bewteen cables and earth 
                //   A
	            double aToE;
                //   B
	            double bToE;
                //   C
	            double cToE;
                //   Neutral
	            double nToE;
            };

            // -----------------------------------------------------------------
            // LineConfiguration
            // -----------------------------------------------------------------
            class LineConfiguration 
            {
                Conductor* phaseAConductor;
	            Conductor* phaseBConductor;
	            Conductor* phaseCConductor;
	            Conductor* phaseNConductor;
                LineSpacing* lineSpacing;

                // Define the z-bus matrix
	            MatrixC3x3 impedance;



            };


            // -----------------------------------------------------------------
            // LineElement
            // -----------------------------------------------------------------
            class LineElement : public EdgeElement
            {
            public:
                double length;
                LineConfiguration *configuration;

            };

            // -----------------------------------------------------------------
            // SwitchMode
            // -----------------------------------------------------------------
            enum class SwitchBankMode
            {
                Individual = 0,
                Banked = 1
            };

            // -----------------------------------------------------------------
            // SwitchState
            // -----------------------------------------------------------------
            enum class SwitchState
            {
                Open = 0,
                Closed = 1,
                Faulted = 2
            };


            // -----------------------------------------------------------------
            // SwitchElement
            // -----------------------------------------------------------------
            class SwitchElement : public EdgeElement
            {
            public:
                SwitchBankMode switchBankMode;
                SwitchBankMode prefaultSwitchBankMode;
	            
                SwitchState phaseAState;
	            SwitchState phaseBState;
	            SwitchState phaseCState;

            };
            
            // -----------------------------------------------------------------
            // RecloserElement
            // -----------------------------------------------------------------
            class RecloserElement : public SwitchElement
            {
            public:
                DateTime retryTime;
	            int maxTries;
	            int currentTry;
	            DateTime returnTime;
	            DateTime previousRecoveryTime;
            };


            // -----------------------------------------------------------------
            // RegulatorConnectionType
            // -----------------------------------------------------------------
            enum class RegulatorConnectionType
            {
                WyeWye = 1,
		        OpenDeltaABBC,
		        OpenDeltaBCAC,
		        OpenDeltaCABA,
		        ClosedDelta,
		        ConnectTypeMax
            };


            // -----------------------------------------------------------------
            // RegulatorControl
            // -----------------------------------------------------------------
            enum class RegulatorControl
            {
                Manual = 1,
		        OutputVoltage = 2,
		        RemoteNode = 3,
		        LineDropComp = 4
            };

            // -----------------------------------------------------------------
            // RegulatorBankMode
            // -----------------------------------------------------------------
            enum class RegulatorBankMode
            {
                Individual = 0,
                Banked = 1
            };
            // -----------------------------------------------------------------
            // RegulatorType
            // -----------------------------------------------------------------
            enum class RegulatorType
            {
                A = 1,
		        B = 2
            };

            // -----------------------------------------------------------------
            // RegulatorConfiguration
            // -----------------------------------------------------------------
            class RegulatorConfiguration
            {
            public:
	            RegulatorControl control;
	            RegulatorBankMode bankMode;
	            RegulatorType type;
	            RegulatorConnectionType connectionType;

	            // band center for regulator control
	            double bandCenter;
                // band width for regulator control
	            double bandWidth;
                // time delay for regulator control
	            double dwellTime;
                // mechanical delay between tap changes 
	            double timeDelay;
                // the number of raise taps
	            short raiseTaps;
                // the number of lower taps
	            short lowerTaps;
                // current transformer rating 
	            double CTRatio;
                // potential transformer rating 
	            double PTRatio;
                // Line Drop Compensation R in volts
	            VectorD3 lineDropCompensationR;
                // Line Drop Compensation X in volts
	            VectorD3 lineDropCompensationX;

                // monitored phases 
                //   by CT
	            Phase phasesCT;
                //   by PT
	            Phase phasesPT;

                // voltage regulation in %
	            double regulation;

	            std::array<short,3> tapPositions;


            };

            // -----------------------------------------------------------------
            // RegulatorTap
            // -----------------------------------------------------------------
            class RegulatorTap
            {
            public:
                short position;
                short previousPosition;
                complex volt;
                complex compensation;
                complex current;
                double changes;

                // next time step after change
                TimeSpan timeDelay;	 
                // advance only after sensing over/under 
                // voltage for a certain dwellTime
	            TimeSpan dwellTime;	 
	            // indicates whether a state change is 
                // okay due to mechanical tap changes
	            short  mechanicalFlag;		 
                // indicates whether a state change is 
                // okay due to dwell time limitations
	            short  dwellFlag;	 
                // prevents the system from failing due to 
                // a bad guess at the initial tap position
	            short  firstRunFlag; 
                // Voltage that is checked with
	            complex checkVoltage;

            };

            // -----------------------------------------------------------------
            // RegulatorElement
            // -----------------------------------------------------------------
            class RegulatorElement : public EdgeElement
            {
            public:
                RegulatorConfiguration* configuration;
                RegulatorTap A;
                RegulatorTap B;
                RegulatorTap C;

                double voltageTapChange;
	            double tapChangePer;
                Range<double> voltageLimits;
	            MatrixC3x3 D;
	            MatrixC3x3 W;
	            
                // Remote node voltage values 
                // in RemoteNode Control mode
	            NodeElement *remoteNode; 
	            
                // final return for next time step
	            TimeSpan nextTime;		 
	            
                // detect off-nominal timesteps and 
                // perform do exception on them
                bool offNominalTime;	

            };


            // -----------------------------------------------------------------
            // TransformerConnectionType
            // -----------------------------------------------------------------
            enum class TransformerConnectionType
            {
                WyeWye = 1, 
                DeltaDelta, 
                DeltaGWye, 
                SinglePhase, 
                SinglePhaseCenterTapped
            };

            // -----------------------------------------------------------------
            // TransformerInstallationType
            // -----------------------------------------------------------------
            enum class TransformerInstallationType
            {
                PoleTop = 1, 
                PadMount, 
                Vault
            };

            // -----------------------------------------------------------------
            // TransformerCoolantType
            // -----------------------------------------------------------------
            enum class TransformerCoolantType
            {
                MineralOil = 1,
                Dry = 2
            };

            // -----------------------------------------------------------------
            // TransformerCoolingType
            // -----------------------------------------------------------------
            enum class TransformerCoolingType
            {
                OA=1, 
                FA=2, 
                NDFOA=3, 
                NDFOW=4, 
                DFOA=5, 
                DFOW=6
            };


            // -----------------------------------------------------------------
            // TransformerConfiguration
            // -----------------------------------------------------------------
            class TransformerConfiguration
            {
            public:
                TransformerConnectionType connectionType;
	            TransformerInstallationType installationType;
                // primary voltage level
	            double primaryVoltage;
                // secondary voltage level kV
	            double secondaryVoltage;   
	            
                // kVA rating of transformer
	            double phaseAkVARating;
	            double phaseBkVARating;
	            double phaseCkVARating;
                // Series impedance
	            std::vector<complex> impedance;
                // Shunt impedance - values are summed 
                // and reflected back to the primary
	            complex shuntImpedance;	
                // alternative way for specifying 
                // transformer impedances
	            double noLoadLoss;
	            double fullLoadLoss;			
                // the reactance to resistance ratio
	            double RX;
	            // thermal model input
	            TransformerCoolantType coolantType;
	            TransformerCoolingType coolingType;
                // Weight of the core & coil assembly
	            double coreCoilWeight;		
                // Weight of the tank & fittings
	            double tankFittingsWeight;
                // Volume of oil in the transformer
	            double oilVolume;
                // The rated winding time constant in hours.
	            double ratedWindingTime;
                // Top-oil hotspot rise over the 
                // ambient temperature at the rated load
	            double topOilDTheta;
                // Winding hotspot rise over the 
                // ambient temperature at the rated load
	            double windingDTheta;
                // Normal lifetime of transformer insulation 
                // at the rated load
                TimeSpan insulationLifeTime;
            };

            // -----------------------------------------------------------------
            // TransformerInsulation
            // -----------------------------------------------------------------
            class TransformerInsulation
            {
            public:
                // aging rate for the transformer insulation. 
	            double insulationAgingFactor;
                // aging acceleration factor.
	            double insulationAgingAccelerationFactor;
                // equivalent aging acceleration factor.
	            double insulationEquivalentAgingAccelerationFactor;
                
                // the installed insulation life of the transformer.
	            TimeSpan insulationLifetime;
                // percent loss of life.
	            double lifeLoss;
            };

            // -----------------------------------------------------------------
            // TransformerThermalModel
            // -----------------------------------------------------------------
            class TransformerThermalModel
            {
            public:
                double thermalCapacity;
                // ratio of the current load to the rated load, per unit.
	            double K;
                // derived exponent for calculating the 
                // variation of windingDTheta with changes 
                // in the load
	            double m;
                // derived exponent for calculating the 
                // variation of topOilDTheta with changes 
                // in the load
	            double n;
                // ratio of the full load loss 
                // to the no-load loss.
	            double R;
                // ambient temperature.
	            double ambientTemperature;
                // winding hotspot temperature
	            double windingTheta;
                // top-oil hotspot temperature
	            double topOilTheta;

                // winding hotspot rise over the 
                // top-oil temperature
	            double windingDTheta;
                // initial winding hotspot rise over the 
                // top-oil temperature
	            double windingInitialDTheta;
                // winding hotspot rise over the top-oil 
                // temperature at the rated load
	            double windingDThetaR;
                // ultimate winding hotspot rise over the top-oil 
                // temperature for current load
	            double windingDThetaU;

                // top-oil hotspot rise over the 
                // ambient temperature
	            double topOilDTheta;
                // initial top-oil hotspot rise over 
                // the ambient temperature
	            double topOilInitialDTheta;
                // ultimate top-oil hotspot rise over the 
                // ambient temperature for the current load
	            double topOilDThetaU;

                // the oil time constant for the rated 
                // load with topOilInitialDTheta = 0
	            TimeSpan topOilRatedTime;
                // the oil time constant for any load and any 
                // difference between topOilDThetaU and topOilInitialDTheta
	            TimeSpan topOilTime;
            };

            // -----------------------------------------------------------------
            // TransformerElement
            // -----------------------------------------------------------------
            class TransformerElement : public EdgeElement
            {
            public:
                TransformerConfiguration* configuration;
                
                // enable the thermal model.
	            bool useThermalModel;
                TransformerThermalModel thermalModel;
	            TransformerInsulation insulation;
                
	            TimeSpan transformerReplacements;
                // timestep before updating the models
	            TimeSpan agingStep;
	            DateTime returnAt;
            };


            // -----------------------------------------------------------------
            // FuseState
            // -----------------------------------------------------------------
            enum class FuseState
            {
                Blown = 0,
                Good  = 1
            };

            // -----------------------------------------------------------------
            // FuseMeanTimeToRestore
            // -----------------------------------------------------------------
            enum class FuseMeanTimeToRestoreType
            {
                None = 0,
                Exponential = 1
            };

            // -----------------------------------------------------------------
            // FuseElement
            // -----------------------------------------------------------------
            class FuseElement : public EdgeElement
            {
            public:
	            FuseMeanTimeToRestoreType restoreType;
                FuseState phaseAState;
	            FuseState phaseBState;
	            FuseState phaseCState;

                // Current limit for the fuse
	            double currentLimit;
	            
	            TimeSpan meanReplacementTime;
	            

            };


            // -----------------------------------------------------------------
            // RelayElement
            // -----------------------------------------------------------------
            class RelayElement : public EdgeElement
            {
            public:
                DateTime relayTime;

                // time for state to change
	            TimeSpan timeToChange;
                // time delay before relay
	            TimeSpan relayDelay;
                // number of times relay has tried
	            short relayTries;	
                // maximum number of relay tries
	            short relayLimit;
	            
                bool relayEvent;

            };


            // -----------------------------------------------------------------
            // SectionalizerElement
            // -----------------------------------------------------------------
            class SectionalizerElement : public SwitchElement
            {
            public:
                

            };

            // -----------------------------------------------------------------
            // SeriesReactorElement
            // -----------------------------------------------------------------
            class SeriesReactorElement : public EdgeElement
            {
            public:
                // impedance of the reactor
                complex phaseAImpedance;
	            complex phaseBImpedance;
	            complex phaseCImpedance;
                // Current rating
	            double ratedCurrentLimit;

            };



            // -----------------------------------------------------------------
            // Node
            // -----------------------------------------------------------------
            class Edge;
            class NodeData;
            class Node
            {
                mutable NodeData* data;
                const NodeData* Data() const;
                NodeData* Data();
            public:
                Node();
                Node(const Node& other);
                Node(Node&& other);
                ~Node( );

                Node& operator = (const Node& other);
                Node& operator = (Node&& other);

                operator bool() const { return data != nullptr; } 

                String Name() const;
                Node& SetName( const String& theName );

                Phase Phases() const;
                Node& SetPhases( Phase thePhases );

	            Phase OriginalPhases() const;
                Node& SetOriginalPhases( Phase theOriginalPhases );

                NodeElementType Type() const;
                Node& SetType(NodeElementType theNodeType);

                Node ParentNode() const;
                Node& SetParentNode(const Node& theParentNode  );

                const std::vector<Node>& ChildNodes() const;
                std::vector<Node>& ChildNodes();

                // edges connecting to this node
                const std::vector<Edge>& Edges() const;
                std::vector<Edge>& Edges();

                // voltage (V)
                const std::vector< complex >& Voltage() const;
                std::vector< complex >& Voltage();

                // constant power (S)
                const std::vector< complex >& Power() const;
                std::vector< complex >& Power();


                // constant admittance/impedance loads (Y)
                const std::vector< complex >& Admittance() const;
                std::vector< complex >& Admittance();

                // constant current (I)
                const std::vector< complex >& Current() const;
                std::vector< complex >& Current();

                // differently-connected children or triplex calculations
                const std::vector< complex >& TriplexData() const;
                std::vector< complex >& TriplexData();

                // nominal residence current 
                const std::vector< complex > ResidenceData() const;
                std::vector< complex > ResidenceData();
                    
                // total real power load (PL)
                const VectorD3& PL() const;
                VectorD3& PL();
                // total reactive power load (QL)
                const VectorD3& QL() const;
                VectorD3& QL();
                // real power generation (for a generator) (PG)
                const VectorD3& PG() const;
                VectorD3& PG();
                // reactive power generation (for a generator) (QG)
                const VectorD3& QG() const;
                VectorD3& QG();

                // kV basis
                double KvBasis() const;
                Node& SetKvBasis( double theValue );
                // MVA basis
                double MVABasis() const;
                Node& SetMVABasis(double theValue);

                // Jacobian matrix work variables
                const std::array< VectorD3,4>& Jacobian() const;
                std::array< VectorD3,4>& Jacobian();
                
                // Maximum voltage error for the node
                double MaxVoltageError() const;
                Node& SetMaxVoltageError( double theValue );

                // Index in matrices
                unsigned Index() const;
                Node& SetIndex(unsigned theValue );


            };


            enum class EdgeType
            {
                UGOHline = 0, 
                TriplexLine = 1, 
                Switch = 2, 
                Fuse = 3, 
                Transformer = 4, 
                Sectionalizer = 5, 
                Recloser = 6
            };

            // -----------------------------------------------------------------
            // Edge
            // -----------------------------------------------------------------
            class EdgeData;
            class Edge
            {
                mutable EdgeData* data;
                const EdgeData* Data() const;
                EdgeData* Data();
            public:
                Edge();
                Edge(const Edge& other);
                Edge(Edge&& other);
                ~Edge( );

                Edge& operator = (const Edge& other);
                Edge& operator = (Edge&& other);

                operator bool() const { return data != nullptr; } 

                String Name() const;
                Edge& SetName( const String& theName );

                Phase Phases() const;
                Edge& SetPhases( Phase thePhases );

	            Phase OriginalPhases() const;
                Edge& SetOriginalPhases( Phase theOriginalPhases );


                EdgeType Type() const;
                Edge& SetType(EdgeType theValue);

                Node From();
                Edge& SetFrom(const Node& theNode);

                Node To() const;
                Edge& SetTo(const Node& theNode);

                // induced faults, prevent restoration of edge
	            Phase FaultPhases() const;
                Edge& SetFaultPhases(Phase theValue);

                // edge admittance of the from side
                const std::vector< complex >& AdmittanceFrom() const;
                std::vector< complex >& AdmittanceFrom();
                // edge admittance of the to side
	            const std::vector< complex >& AdmittanceTo() const;
                std::vector< complex >& AdmittanceTo();
                // self admittance seen on from side
	            const std::vector< complex >& SelfAdmittanceFrom() const;
                std::vector< complex >& SelfAdmittanceFrom();
                // self admittance on the to side
	            const std::vector< complex >& SelfAdmittanceTo() const;
                std::vector< complex >& SelfAdmittanceTo();
                // 3 phase fault currents on the from side
	            const std::vector< complex >& FaultCurrentsFrom() const;
                std::vector< complex >& FaultCurrentsFrom();
                // 3 phase fault currents on the to side 
	            const std::vector< complex >& FaultCurrentsTo() const;
                std::vector< complex >& FaultCurrentsTo();

                // from/to voltage ratio
                double VoltageRatio() const;
                Edge& SetVoltageRatio(double theValue);

                // Next faulted edge below the current edge
                Edge FaultEdge() const;
                Edge& SetFaultEdge(const Edge& theFaultEdge);

                // Edge (switch) status
                const std::vector<bool>& Status() const;
                std::vector<bool>& Status();


            };



            // -----------------------------------------------------------------
            // BaseData
            // -----------------------------------------------------------------
            class BaseData 
            {
                long referenceCount;
                String name;
	            Phase phases;
	            Phase originalPhases;
            public:
                BaseData()
                    : referenceCount(1),
                      phases(Phase::None),
                      originalPhases(Phase::None)
                {}

                virtual ~BaseData()
                {}

                long AddRef()
                {
                    return InterlockedIncrement(&referenceCount);
                }

                long Release()
                {
                    long result = InterlockedDecrement(&referenceCount);
                    if(!result)
                    {
                        delete this;
                    }
                    return result;
                }


                String Name() const { return name; }
                BaseData& SetName( const String& theName )
                {
                    name = theName;
                    return *this;
                }

                Phase Phases() const { return phases; }
                BaseData& SetPhases( Phase thePhases )
                {
                    phases = thePhases;
                    return *this;
                }

	            Phase OriginalPhases() const { return originalPhases; }
                BaseData& SetOriginalPhases( Phase theOriginalPhases )
                {
                    originalPhases = theOriginalPhases;
                    return *this;
                }

            };

            // -----------------------------------------------------------------
            // NodeData
            // -----------------------------------------------------------------
            class NodeData : public BaseData 
            {
	            NodeElementType nodeType;

                Node parentNode;
	            std::vector<Node> childNodes;
                std::vector<Node>::iterator childNode;

                // edges connecting to this node
                std::vector<Edge> edges;

                // voltage (V)
                std::vector< complex > voltage;
                // constant power (S)
	            std::vector< complex > power;
                // constant admittance/impedance loads (Y)
	            std::vector< complex > admittance;
                // constant current (I)
	            std::vector< complex > current;

                // differently-connected children or triplex calculations
	            std::vector< complex > triplexData;
                // nominal residence current 
	            std::vector< complex > residenceData;
                    
                // total real power load (PL)
	            VectorD3 totalRealPowerLoad;
                // total reactive power load (QL)
	            VectorD3 totalReactivePowerLoad;
                // real power generation (for a generator) (PG)
	            VectorD3 totalRealGeneratedPower;
                // reactive power generation (for a generator) (QG)
	            VectorD3 totalReactiveGeneratedPower;
                // kV basis
	            double kvBasis;
                // MVA basis
                double mvaBasis;

                // Jacobian matrix work variables
                std::array< VectorD3,4> jacobian;

                
                // Maximum voltage error for the node
	            double maxVoltageError;	

                // Index in matrices
	            unsigned index;
            public:
                NodeData()
                    : nodeType(NodeElementType::PQ),
                      kvBasis(0.0),
                      mvaBasis(0.0),
                      maxVoltageError(0.0),
                      index(0)
                {
                }



                NodeElementType Type() const { return nodeType; }
                void SetType(NodeElementType theNodeType) { nodeType = theNodeType; }

                Node ParentNode() const { return parentNode; }
                void SetParentNode(const Node& theParentNode  ) { parentNode = theParentNode; }

                const std::vector<Node>& ChildNodes() const { return childNodes; }
                std::vector<Node>& ChildNodes() { return childNodes; }

                // edges connecting to this node
                const std::vector<Edge>& Edges() const { return edges; }
                std::vector<Edge>& Edges() { return edges; }

                // voltage (V)
                const std::vector< complex >& Voltage() const { return voltage; }
                std::vector< complex >& Voltage() { return voltage; }

                // constant power (S)
                const std::vector< complex >& Power() const { return power; }
                std::vector< complex >& Power() { return power; }


                // constant admittance/impedance loads (Y)
                const std::vector< complex >& Admittance() const { return admittance; }
                std::vector< complex >& Admittance() { return admittance; }

                // constant current (I)
                const std::vector< complex >& Current() const { return current; }
                std::vector< complex >& Current() { return current; }

                // differently-connected children or triplex calculations
                const std::vector< complex >& TriplexData() const { return triplexData; }
                std::vector< complex >& TriplexData() { return triplexData; }

                // nominal residence current 
                const std::vector< complex > ResidenceData() const { return residenceData; }
                std::vector< complex > ResidenceData() { return residenceData; }
                    
                // total real power load (PL)
                const VectorD3& PL() const { return totalRealPowerLoad; }
                VectorD3& PL() { return totalRealPowerLoad; }
                // total reactive power load (QL)
                const VectorD3& QL() const { return totalReactivePowerLoad; }
                VectorD3& QL() { return totalReactivePowerLoad; }
                // real power generation (for a generator) (PG)
                const VectorD3& PG() const { return totalRealGeneratedPower; }
                VectorD3& PG() { return totalRealGeneratedPower; }
                // reactive power generation (for a generator) (QG)
                const VectorD3& QG() const { return totalReactiveGeneratedPower; }
                VectorD3& QG() { return totalReactiveGeneratedPower; }

                // kV basis
                double KvBasis() const { return kvBasis; }
                void SetKvBasis( double theValue ) { kvBasis = theValue; }
                // MVA basis
                double MVABasis() const { return mvaBasis; }
                void SetMVABasis(double theValue) { mvaBasis = theValue; }

                // Jacobian matrix work variables
                const std::array< VectorD3,4>& Jacobian() const { return jacobian; }
                std::array< VectorD3,4>& Jacobian() { return jacobian; }
                
                // Maximum voltage error for the node
                double MaxVoltageError() const { return maxVoltageError; }
                void SetMaxVoltageError( double theValue ) { maxVoltageError = theValue; }

                // Index in matrices
                unsigned Index() const { return index; }
                void SetIndex(unsigned theValue ) { index = theValue; }
            };


            // -----------------------------------------------------------------
            // EdgeData
            // -----------------------------------------------------------------
            class EdgeData : public BaseData 
            {
                EdgeType type;

                Node from;
	            Node to;

                // induced faults, prevent restoration of edge
	            Phase faultPhases;

                // edge admittance of the from side
                std::vector< complex > admittanceFrom;
                // edge admittance of the to side
	            std::vector< complex > admittanceTo;
                // self admittance seen on from side
	            std::vector< complex > selfAdmittanceFrom;
                // self admittance on the to side
	            std::vector< complex > selfAdmittanceTo;
                // 3 phase fault currents on the from side
	            std::vector< complex > faultCurrentsFrom;
                // 3 phase fault currents on the to side 
	            std::vector< complex > faultCurrentsTo;

                // from/to voltage ratio
	            double voltageRatio;

                // Next faulted edge below the current edge
	            Edge faultEdge;
                // Edge (switch) status
	            std::vector<bool> status;
            public:

	            
                EdgeType Type() const { return type; }
                void SetType(EdgeType theValue) { type = theValue; }

                Node From() const
                {
                    return from;
                }
                void SetFrom(const Node& theNode) { from = theNode; }

                Node To() const { return to; }
                void SetTo(const Node& theNode) { to = theNode; }

                // induced faults, prevent restoration of edge
	            Phase FaultPhases() const
                {
                    return faultPhases;
                }

                void SetFaultPhases(Phase theValue) { faultPhases = theValue; }

                // edge admittance of the from side
                const std::vector< complex >& AdmittanceFrom() const { return admittanceFrom; }
                std::vector< complex >& AdmittanceFrom() { return admittanceFrom; }
                // edge admittance of the to side
	            const std::vector< complex >& AdmittanceTo() const { return admittanceTo; }
                std::vector< complex >& AdmittanceTo() { return admittanceTo; }
                // self admittance seen on from side
	            const std::vector< complex >& SelfAdmittanceFrom() const { return selfAdmittanceFrom; }
                std::vector< complex >& SelfAdmittanceFrom() { return selfAdmittanceFrom; }
                // self admittance on the to side
	            const std::vector< complex >& SelfAdmittanceTo() const { return selfAdmittanceTo; }
                std::vector< complex >& SelfAdmittanceTo() { return selfAdmittanceTo; }
                // 3 phase fault currents on the from side
	            const std::vector< complex >& FaultCurrentsFrom() const { return faultCurrentsFrom; }
                std::vector< complex >& FaultCurrentsFrom() { return faultCurrentsFrom; }
                // 3 phase fault currents on the to side 
	            const std::vector< complex >& FaultCurrentsTo() const { return faultCurrentsTo; }
                std::vector< complex >& FaultCurrentsTo() { return faultCurrentsTo; }

                // from/to voltage ratio
                double VoltageRatio() const { return voltageRatio; }
                void SetVoltageRatio(double theValue) { voltageRatio = theValue; }

                // Next faulted edge below the current edge
                Edge FaultEdge() const { return faultEdge; }
                void SetFaultEdge(const Edge& theValue) { faultEdge = theValue; }

                // Edge (switch) status
                const std::vector<bool>& Status() const { return status; }
                std::vector<bool>& Status() { return status; }

            };

            // -----------------------------------------------------------------
            // SolverData
            // -----------------------------------------------------------------
            class SolverData
            {
                long referenceCount;
                std::vector< Node > nodes;
                std::vector< Edge > edges;
                bool errors;
                long long iterations;
            public:

                SolverData()
                    : referenceCount(1)
                {}

                SolverData(const std::vector< Node >& theNodes, const std::vector< Edge >& theEdges )
                    : referenceCount(1),
                      nodes(theNodes),
                      edges(theEdges)
                {}

                long AddRef()
                {
                    return InterlockedIncrement(&referenceCount);
                }

                long Release()
                {
                    long result = InterlockedDecrement(&referenceCount);
                    if(!result)
                    {
                        delete this;
                    }
                    return result;
                }

                HPWR_EXPORT void Solve();
                HPWR_EXPORT bool HasSolution() const;

                const std::vector< Node > Nodes() const { return nodes; }
                std::vector< Node > Nodes() { return nodes; }

                const std::vector< Edge > Edges() const { return edges; }
                std::vector< Edge > Edges() { return edges; }

                long long Result() const { return iterations; }

            };

            // -----------------------------------------------------------------
            // Solver
            // -----------------------------------------------------------------
            class Solver
            {
                SolverData* data;
            public:
                Solver()
                    : data(new SolverData())
                {}

                Solver(const std::vector< Node >& theNodes, const std::vector< Edge >& theEdges)
                    : data(new SolverData(theNodes,theEdges))
                {}

                Solver& Solve() 
                {
                    data->Solve();
                    return *this;
                }
                bool HasSolution() const
                {
                    return data->HasSolution();
                }

                const std::vector< Node > Nodes() const { return data->Nodes(); }
                std::vector< Node > Nodes() { return data->Nodes(); }

                const std::vector< Edge > Edges() const { return data->Edges(); }
                std::vector< Edge > Edges() { return data->Edges(); }

                long long Result() const { return data->Result(); }



            };


            // -----------------------------------------------------------------
            // Node implementation
            // -----------------------------------------------------------------
            const NodeData* Node::Data() const
            {
                if(!data)
                {
                    data = new NodeData();
                }
                return data;
            }
            NodeData* Node::Data()
            {
                if(!data)
                {
                    data = new NodeData();
                }
                return data;
            }

            inline Node::Node()
                : data(nullptr)
            {}
            inline Node::Node(const Node& other)
                : data(other.data)
            {
                if(data)
                {
                    data->AddRef();
                }
            }
            inline Node::Node(Node&& other)
                : data(other.data)
            {
                other.data = nullptr;
            }
            inline Node::~Node( )
            {
                if(data)
                {
                    data->Release();
                }
            }

            inline Node& Node::operator = (const Node& other)
            {
                if(data != other.data)
                {
                    if(data)
                    {
                        data->Release();
                    }
                    data = other.data;
                    if(data)
                    {
                        data->AddRef();
                    }
                }
                return *this;
            }
            inline Node& Node::operator = (Node&& other)
            {
                if(this != &other)
                {
                    if(data)
                    {
                        data->Release();
                    }
                    data = other.data;
                    if(data)
                    {
                        data->AddRef();
                    }
                }
                return *this;
            }


            inline String Node::Name() const
            {
                return Data()->Name();
            }
            inline Node& Node::SetName( const String& theName )
            {
                Data()->SetName(theName);
                return *this;
            }

            inline Phase Node::Phases() const
            {
                return Data()->Phases();
            }
            inline Node& Node::SetPhases( Phase thePhases )
            {
                Data()->SetPhases(thePhases);
                return *this;
            }

	        inline Phase Node::OriginalPhases() const
            {
                return Data()->OriginalPhases();
            }
            inline Node& Node::SetOriginalPhases( Phase theOriginalPhases )
            {
                Data()->SetOriginalPhases(theOriginalPhases);
                return *this;
            }

            inline NodeElementType Node::Type() const
            {
                return Data()->Type();
            }
            inline Node& Node::SetType(NodeElementType theNodeType)
            {
                Data()->SetType(theNodeType);
                return *this;
            }

            inline Node Node::ParentNode() const
            {
                return Data()->ParentNode();
            }
            inline Node& Node::SetParentNode(const Node& theParentNode  )
            {
                Data()->SetParentNode(theParentNode);
                return *this;
            }

            inline const std::vector<Node>& Node::ChildNodes() const
            {
                return Data()->ChildNodes();
            }
            inline std::vector<Node>& Node::ChildNodes()
            {
                return Data()->ChildNodes();
            }

            // edges connecting to this node
            inline const std::vector<Edge>& Node::Edges() const
            {
                return Data()->Edges();
            }
            inline std::vector<Edge>& Node::Edges()
            {
                return Data()->Edges();
            }

            // voltage (V)
            inline const std::vector< complex >& Node::Voltage() const
            {
                return Data()->Voltage();
            }
            inline std::vector< complex >& Node::Voltage()
            {
                return Data()->Voltage();
            }

            // constant power (S)
            inline const std::vector< complex >& Node::Power() const
            {
                return Data()->Power();
            }
            inline std::vector< complex >& Node::Power()
            {
                return Data()->Power();
            }


            // constant admittance/impedance loads (Y)
            inline const std::vector< complex >& Node::Admittance() const
            {
                return Data()->Admittance();
            }
            inline std::vector< complex >& Node::Admittance()
            {
                return Data()->Admittance();
            }

            // constant current (I)
            inline const std::vector< complex >& Node::Current() const
            {
                return Data()->Current();
            }
            inline std::vector< complex >& Node::Current()
            {
                return Data()->Current();
            }

            // differently-connected children or triplex calculations
            inline const std::vector< complex >& Node::TriplexData() const
            {
                return Data()->TriplexData();
            }
            inline std::vector< complex >& Node::TriplexData()
            {
                return Data()->TriplexData();
            }

            // nominal residence current 
            inline const std::vector< complex > Node::ResidenceData() const
            {
                return Data()->ResidenceData();
            }
            inline std::vector< complex > Node::ResidenceData()
            {
                return Data()->ResidenceData();
            }
                    
            // total real power load (PL)
            inline const VectorD3& Node::PL() const
            {
                return Data()->PL();
            }
            inline VectorD3& Node::PL()
            {
                return Data()->PL();
            }
            // total reactive power load (QL)
            inline const VectorD3& Node::QL() const
            {
                return Data()->QL();
            }
            inline VectorD3& Node::QL()
            {
                return Data()->QL();
            }
            // real power generation (for a generator) (PG)
            inline const VectorD3& Node::PG() const
            {
                return Data()->PG();
            }
            inline VectorD3& Node::PG()
            {
                return Data()->PG();
            }
            // reactive power generation (for a generator) (QG)
            inline const VectorD3& Node::QG() const
            {
                return Data()->QG();
            }
            inline VectorD3& Node::QG()
            {
                return Data()->QG();
            }

            // kV basis
            inline double Node::KvBasis() const
            {
                return Data()->KvBasis();
            }
            inline Node& Node::SetKvBasis( double theValue )
            {
                Data()->SetKvBasis( theValue );
                return *this;
            }
            // MVA basis
            inline double Node::MVABasis() const
            {
                return Data()->MVABasis();
            }
            inline Node& Node::SetMVABasis(double theValue)
            {
                Data()->SetMVABasis( theValue );
                return *this;
            }

            // Jacobian matrix work variables
            inline const std::array< VectorD3,4>& Node::Jacobian() const
            {
                return Data()->Jacobian();
            }

            inline std::array< VectorD3,4>& Node::Jacobian()
            {
                return Data()->Jacobian();
            }

                
            // Maximum voltage error for the node
            inline double Node::MaxVoltageError() const
            {
                return Data()->MaxVoltageError();
            }
            inline Node& Node::SetMaxVoltageError( double theValue )
            {
                Data()->SetMaxVoltageError( theValue );
                return *this;
            }

            // Index in matrices
            inline unsigned Node::Index() const
            {
                return Data()->Index();
            }

            inline Node& Node::SetIndex(unsigned theValue )
            {
                Data()->SetIndex( theValue );
                return *this;
            }

            // -----------------------------------------------------------------
            // Edge implementation
            // -----------------------------------------------------------------
            const EdgeData* Edge::Data() const
            {
                if(!data)
                {
                    data = new EdgeData();
                }
                return data;
            }
            EdgeData* Edge::Data()
            {
                if(!data)
                {
                    data = new EdgeData();
                }
                return data;
            }

            
            Edge::Edge()
                : data(nullptr)
            {}
            Edge::Edge(const Edge& other)
                : data(other.data)
            {
                if(data)
                {
                    data->AddRef();
                }
            }
            Edge::Edge(Edge&& other)
                : data(other.data)
            {
                other.data = nullptr;
            }
            Edge::~Edge( )
            {
                if(data)
                {
                    data->Release();
                }
            }

            inline Edge& Edge::operator = (const Edge& other)
            {
                if(data != other.data)
                {
                    if(data)
                    {
                        data->Release();
                    }
                    data = other.data;
                    if(data)
                    {
                        data->AddRef();
                    }
                }
                return *this;
            }
            inline Edge& Edge::operator = (Edge&& other)
            {
                if(this != &other)
                {
                    if(data)
                    {
                        data->Release();
                    }
                    data = other.data;
                    if(data)
                    {
                        data->AddRef();
                    }
                }
                return *this;
            }


            inline String Edge::Name() const
            {
                return Data()->Name();
            }
            inline Edge& Edge::SetName( const String& theName )
            {
                Data()->SetName(theName);
                return *this;
            }

            inline Phase Edge::Phases() const
            {
                return Data()->Phases();
            }
            inline Edge& Edge::SetPhases( Phase thePhases )
            {
                Data()->SetPhases(thePhases);
                return *this;
            }

	        inline Phase Edge::OriginalPhases() const
            {
                return Data()->OriginalPhases();
            }
            inline Edge& Edge::SetOriginalPhases( Phase theOriginalPhases )
            {
                Data()->SetOriginalPhases(theOriginalPhases);
                return *this;
            }


            EdgeType Edge::Type() const
            {
                return Data()->Type();
            }
            Edge& Edge::SetType(EdgeType theValue)
            {
                Data()->SetType(theValue);
                return *this;
            }

            Node Edge::From()
            {
                return Data()->From();
            }
            Edge& Edge::SetFrom(const Node& theNode)
            {
                Data()->SetFrom(theNode);
                return *this;
            }

            Node Edge::To() const
            {
                return Data()->To();
            }
            Edge& Edge::SetTo(const Node& theNode)
            {
                Data()->SetTo(theNode);
                return *this;
            }

            // induced faults, prevent restoration of edge
	        Phase Edge::FaultPhases() const
            {
                return Data()->FaultPhases();
            }
            Edge& Edge::SetFaultPhases(Phase theValue)
            {
                Data()->SetFaultPhases(theValue);
                return *this;
            }

            // edge admittance of the from side
            const std::vector< complex >& Edge::AdmittanceFrom() const
            {
                return Data()->AdmittanceFrom();
            }
            std::vector< complex >& Edge::AdmittanceFrom()
            {
                return Data()->AdmittanceFrom();
            }
            // edge admittance of the to side
	        const std::vector< complex >& Edge::AdmittanceTo() const
            {
                return Data()->AdmittanceTo();
            }
            std::vector< complex >& Edge::AdmittanceTo()
            {
                return Data()->AdmittanceTo();
            }
            // self admittance seen on from side
	        const std::vector< complex >& Edge::SelfAdmittanceFrom() const
            {
                return Data()->SelfAdmittanceFrom();
            }
            std::vector< complex >& Edge::SelfAdmittanceFrom()
            {
                return Data()->SelfAdmittanceFrom();
            }
            // self admittance on the to side
	        const std::vector< complex >& Edge::SelfAdmittanceTo() const
            {
                return Data()->SelfAdmittanceTo();
            }
            std::vector< complex >& Edge::SelfAdmittanceTo()
            {
                return Data()->SelfAdmittanceTo();
            }
            // 3 phase fault currents on the from side
	        const std::vector< complex >& Edge::FaultCurrentsFrom() const
            {
                return Data()->FaultCurrentsFrom();
            }
            std::vector< complex >& Edge::FaultCurrentsFrom()
            {
                return Data()->FaultCurrentsFrom();
            }
            // 3 phase fault currents on the to side 
	        const std::vector< complex >& Edge::FaultCurrentsTo() const
            {
                return Data()->FaultCurrentsTo();
            }
            std::vector< complex >& Edge::FaultCurrentsTo()
            {
                return Data()->FaultCurrentsTo();
            }

            // from/to voltage ratio
            double Edge::VoltageRatio() const
            {
                return Data()->VoltageRatio();
            }
            Edge& Edge::SetVoltageRatio(double theValue)
            {
                Data()->SetVoltageRatio(theValue);
                return *this;
            }

            // Next faulted edge below the current edge
            Edge Edge::FaultEdge() const
            {
                return Data()->FaultEdge();
            }
            Edge& Edge::SetFaultEdge(const Edge& theFaultEdge)
            {
                Data()->SetFaultEdge(theFaultEdge);
                return *this;
            }

            // Edge (switch) status
            const std::vector<bool>& Edge::Status() const
            {
                return Data()->Status();
            }
            std::vector<bool>& Edge::Status()
            {
                return Data()->Status();
            }




        };
    };
};



#endif //__HPOWERNETSOLVER_H__
